using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Pikapika.Models;
using System.Text.RegularExpressions;

namespace Pikapika.Areas.Admin.Controllers
{
    public class NovelChapterController : CrudControllerBase<NovelChapter>
    {

        private static Regex _tags = new Regex("<[^>]*(>|$)",
    RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled);
        private static Regex _whitelist = new Regex(@"
    ^</?(b(lockquote)?|code|d(d|t|l|el)|em|h(1|2|3)|i|kbd|li|ol|p(re)?|s(ub|up|trong|trike)?|ul)>$|
    ^<(b|h)r\s?/?>$",
            RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);
        private static Regex _whitelist_a = new Regex(@"
    ^<a\s
    href=""(\#\d+|(https?|ftp)://[-a-z0-9+&@#/%?=~_|!:,.;\(\)]+)""
    (\stitle=""[^""<>]+"")?\s?>$|
    ^</a>$",
            RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);
        private static Regex _whitelist_img = new Regex(@"
    ^<img\s
    src=""https?://[-a-z0-9+&@#/%?=~_|!:,.;\(\)]+""
    (\swidth=""\d{1,3}"")?
    (\sheight=""\d{1,3}"")?
    (\salt=""[^""<>]*"")?
    (\stitle=""[^""<>]*"")?
    \s?/?>$",
            RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);


        /// <summary>
        /// sanitize any potentially dangerous tags from the provided raw HTML input using 
        /// a whitelist based approach, leaving the "safe" HTML tags
        /// CODESNIPPET:4100A61A-1711-4366-B0B0-144D1179A937
        /// </summary>
        private string Sanitize(string html)
        {
            if (String.IsNullOrEmpty(html)) return html;

            if (User.IsInRole("Administrators"))
            {
                return html;
            }

            string tagname;
            Match tag;

            // match every HTML tag in the input
            MatchCollection tags = _tags.Matches(html);
            for (int i = tags.Count - 1; i > -1; i--)
            {
                tag = tags[i];
                tagname = tag.Value.ToLowerInvariant();

                if (!(_whitelist.IsMatch(tagname) || _whitelist_a.IsMatch(tagname) || _whitelist_img.IsMatch(tagname)))
                {
                    html = html.Remove(tag.Index, tag.Length);
                    System.Diagnostics.Debug.WriteLine("tag sanitized: " + tagname);
                }
            }

            return html;
        }


        protected override System.Data.Objects.ObjectSet<NovelChapter> GetObjectSet(PikapikaDBEntities ctx)
        {
            return ctx.NovelChapters;
        }

        protected override IQueryable<NovelChapter> GetObjectQuery(PikapikaDBEntities ctx)
        {
            IQueryable<NovelChapter> query = ctx.NovelChapters.Include("NovelVolume.Novel");
            RouteData.ProcessOptionalId("novelVolumeId", (novelVolumeId) =>
            {
                query = query.Where(n => n.NovelVolumeId == novelVolumeId);
                ViewBag.NovelVolumeId = novelVolumeId;
            });
            return query;
        }


        public ActionResult Create(int novelVolumeId)
        {
            ViewBag.NovelVolumeId = novelVolumeId;
            NovelChapter model = new NovelChapter();
            model.NovelVolumeId = novelVolumeId;
            if (this.User.Identity.IsAuthenticated)
            {
                model.PostUserName = this.User.Identity.Name;
            }
            return View(model);
        }

        [ValidateInput(false)]
        public override ActionResult Create(NovelChapter model)
        {
            model.ChapterContent = Sanitize(model.ChapterContent);
            return base.Create(model);
        }

        [ValidateInput(false)]
        public override ActionResult Edit(int id, NovelChapter model)
        {
            var ret = base.EditImpl(id, model, true);
            model.ChapterContent = Sanitize(model.ChapterContent);
            return ret;
        }

        [ValidateInput(false)]
        [HttpPost]
        public ActionResult EditRichText(int id, NovelChapter model)
        {
            return Edit(id, model);
        }

        public ActionResult EditRichText(int id)
        {
            return Edit(id);
        }

        [NonAction]
        public override ActionResult Create()
        {
            return base.Create();
        }

        public ActionResult CreateBatch(int novelVolumeId)
        {
            ViewBag.PostUserName = User.Identity.IsAuthenticated ? User.Identity.Name : "";
            ViewBag.NovelVolumeId = novelVolumeId;
            return View();
        }

        [HttpPost]
        public ActionResult CreateBatch(IEnumerable<NovelChapter> chapters, int novelVolumeId)
        {
            if (!ModelState.IsValid)
            {
                return Content(@"{""error"": ""Data is not valid.""}");
            }
            if (!chapters.Any())
            {
                return Content(@"{""error"": ""No chapter is added.""}");
            }

            if (!chapters.All(ch => ch.NovelVolumeId == novelVolumeId))
            {
                return Content(@"{""error"": ""All chapters must be in the same volume.""}");
            }

            try
            {
                using (var ctx = new PikapikaDBEntities())
                {
                    foreach (var ch in chapters)
                    {
                        ch.ChapterContent = Sanitize(ch.ChapterContent);
                        ctx.AddToNovelChapters(ch);
                    }
                    ctx.SaveChanges();
                    return Content(string.Format(@"{{""redirectTo"": ""{0}""}}", Url.Action("Index", new { novelVolumeId = novelVolumeId })));
                }
            }
            catch (Exception ex)
            {
                return Content(@"{{""error"": ""{0}""}}", ex.Message);
            }
        }

        public ActionResult CreateBatchRichText(int novelVolumeId)
        {
            return CreateBatch(novelVolumeId);
        }

        [HttpPost]
        public ActionResult CreateBatchRichText(IEnumerable<NovelChapter> chapters, int novelVolumeId)
        {
            return CreateBatch(chapters, novelVolumeId);
        }
    }
}
